1 module common_windows;
2 
3 version(Windows)
4 {
5     pragma(lib, "ole32.lib");
6     pragma(lib, "oleaut32.lib");
7 	import core.sys.windows.objbase;
8 	import core.sys.windows.winbase;
9 	import core.sys.windows.windef;
10 	import core.sys.windows.com;
11 	import core.sys.windows.basetyps;
12 
13 	import core.stdc.wchar_:wcscmp;
14 	import core.sys.windows.oleauto:SysStringLen;
15 	import core.sys.windows.wtypes:BSTR;
16     const GUID iid_SetupConfiguration = { 0x177F0C4A, 0x1CD3, 0x4DE7, [ 0xA3, 0x2C, 0x71, 0xDB, 0xBB, 0x9F, 0xA3, 0x6D ] };
17 
18 	static interface ISetupInstance : IUnknown
19 	{
20 		// static const GUID iid = uuid("B41463C3-8866-43B5-BC33-2B0676F7F42E");
21 		static const GUID iid = { 0xB41463C3, 0x8866, 0x43B5, [ 0xBC, 0x33, 0x2B, 0x06, 0x76, 0xF7, 0xF4, 0x2E ] };
22 
23 		int GetInstanceId(BSTR* pbstrInstanceId);
24 		int GetInstallDate(LPFILETIME pInstallDate);
25 		int GetInstallationName(BSTR* pbstrInstallationName);
26 		int GetInstallationPath(BSTR* pbstrInstallationPath);
27 		int GetInstallationVersion(BSTR* pbstrInstallationVersion);
28 		int GetDisplayName(LCID lcid, BSTR* pbstrDisplayName);
29 		int GetDescription(LCID lcid, BSTR* pbstrDescription);
30 		int ResolvePath(LPCOLESTR pwszRelativePath, BSTR* pbstrAbsolutePath);
31 	}
32 
33 	static interface IEnumSetupInstances : IUnknown
34 	{
35 		// static const GUID iid = uuid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848");
36 
37 		int Next(ULONG celt, ISetupInstance* rgelt, ULONG* pceltFetched);
38 		int Skip(ULONG celt);
39 		int Reset();
40 		int Clone(IEnumSetupInstances* ppenum);
41 	}
42 
43 	static interface ISetupConfiguration : IUnknown
44 	{
45 		// static const GUID iid = uuid("42843719-DB4C-46C2-8E7C-64F1816EFD5B");
46 		static const GUID iid = { 0x42843719, 0xDB4C, 0x46C2, [ 0x8E, 0x7C, 0x64, 0xF1, 0x81, 0x6E, 0xFD, 0x5B ] };
47 
48 		int EnumInstances(IEnumSetupInstances* ppEnumInstances) ;
49 		int GetInstanceForCurrentProcess(ISetupInstance* ppInstance);
50 		int GetInstanceForPath(LPCWSTR wzPath, ISetupInstance* ppInstance);
51 	}
52 
53     bool detectVSInstallDirViaCOM(out wchar[] versionStr, out wchar[] installStr)
54 	{
55 		import commons;
56 		CoInitialize(null); scope(exit) CoUninitialize();
57 
58 		ISetupConfiguration setup;
59     	IEnumSetupInstances instances;
60 		ISetupInstance instance;
61 		DWORD fetched;
62 
63 		HRESULT hr = CoCreateInstance(&iid_SetupConfiguration, null, CLSCTX_ALL, &ISetupConfiguration.iid, cast(void**) &setup);
64 		if(hr != S_OK || !setup) return false;
65 
66 		scope(exit) setup.Release();
67 		if(setup.EnumInstances(&instances) != S_OK)
68 			return false;
69 		scope(exit) instances.Release();
70 
71 		BSTR thisVersionString, thisInstallDir;
72 		while (instances.Next(1, &instance, &fetched) == S_OK && fetched)
73 		{
74 			import std.conv:to;
75 			if(instance.GetInstallationVersion(&thisVersionString) != S_OK ||
76 			instance.GetInstallationPath(&thisInstallDir) != S_OK)
77 				continue;
78             versionStr = thisVersionString[0..SysStringLen(thisVersionString)];
79 			installStr = thisInstallDir[0..SysStringLen(thisInstallDir)];
80 
81 			if(!("vsInstallDir" in configs))
82 			{
83 				configs["vsInstallDir"] = installStr.to!string;
84 				updateConfigFile();
85 			}
86 			return true;
87 		}
88 		return false;
89 	}
90 	bool detectVSInstallDirViaCOM()
91 	{
92 		wchar[] vers, install;
93 		return detectVSInstallDirViaCOM(vers, install);
94 	}
95 }